package com.chunuo.configuration.data;

import com.chunuo.configuration.annotation.TableField;
import com.chunuo.configuration.annotation.TableId;
import com.chunuo.configuration.annotation.TableName;
import com.chunuo.configuration.factory.TransactionManagerUtils;
import com.chunuo.configuration.interfaces.DataVisit;
import com.chunuo.configuration.utils.AnnotationUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 真实实现增删改查功能的类
 */
public class DataQuery  implements DataVisit {

    private QueryRunner queryRunner = new QueryRunner();

    /*
     * 更新、删除、添加数据库操作
     */
    public int update(String sql, Object... args) {

        int count = 0;
        try {
            count = queryRunner.update(TransactionManagerUtils.getConnection(), sql, args);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return count;
    }

    /*
     * 查询单行数据
     */
    public <T> T queryRow(String sql,Class<T> clazz,Object ...args) throws SQLException {
        T t = null;
        try {
            t = queryRunner.query(TransactionManagerUtils.getConnection(), sql, new BeanHandler<T>(clazz),args);
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return t;
    }

    /*
     *  查询多行数据
     */
    public <T> List<T> queryForeach(String sql,Class<T> clazz,Object ...args) {
        List<T> list = new ArrayList<T>();
        try {
            list = queryRunner.query(TransactionManagerUtils.getConnection(), sql, new BeanListHandler<T>(clazz),args);
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return list;
    }

    /*
        查询一个
     */
    public Object getSingle(String sql,Object ...args) {
        Object obj = null;
        try {
            obj = queryRunner.query(TransactionManagerUtils.getConnection(), sql, new ScalarHandler<Object>(),args);
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return obj;
    }

    /**
     * 保存或更新
     * @param obj
     * @return
     */
    @Override
    public int saveOrUpdate(Object obj) {
        return reflectObj(obj);
    }

    /**
     * 删除
     * @param obj
     * @return
     */
    @Override
    public int delete(Object obj){
        return reflectObj(obj);
    }


    /**
     * 实现自带方法的增删改
     * @param obj 需要遍历属性的对象
     * @throws IllegalAccessException
     */
    private int reflectObj(Object obj){

        //调用本方法的方法名（saveOrUpdate、delete、xxx等等）
        String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();

        //sql语句
        StringBuffer sql = new StringBuffer();

        //sql参数部分
        StringBuffer argsNum = new StringBuffer();

        //参数数组 （将对象属性按顺序存到集合中）
        List<Object> list = new ArrayList<>();

        //获取对象的所有属性
        Field[] fields = obj.getClass().getDeclaredFields();

        //表中id字段名
        Object mysqlId = null;
        //实体类id字段名
        Object entityId = null;
        //获取表中id和实体类id
        for(Field field : fields){
            TableId tableId = field.getAnnotation(TableId.class);
            TableField tableField = field.getAnnotation(TableField.class);
            if(tableId==null){
                continue;
            }
            entityId = field.getName();
            if(tableField!=null){
                mysqlId = tableField.value();
            }
        }

        if(entityId==null){
            throw new RuntimeException(obj.getClass()+" 没有@TableId注解");
        }

        //获取对象的id
        Object id = null;
        try {
            Field fieldId = obj.getClass().getDeclaredField(String.valueOf(entityId));
            boolean accessible = fieldId.isAccessible();
            fieldId.setAccessible(true);
            //获取id的值
            id = fieldId.get(obj);
            //把字段修饰符该回去
            fieldId.setAccessible(accessible);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //1：保存、2：更新、3：删除
        int step = autoExecute(obj, sql, methodName,id);

        //记录循环到第几个属性
        int len = 0;
        boolean flag = false;
        for(Field field : fields){
            TableId tableId = field.getAnnotation(TableId.class);
            TableField tableField = field.getAnnotation(TableField.class);
            if(field.toString().indexOf(" static ")!=-1||
                field.toString().indexOf(" final ")!=-1||
                (tableId==null&&tableField==null)) {
                continue;
            }
            //获取TableField注解上的value（数据库字段名）
            String fieldName = tableField.value();
            //如果为空，则采用驼峰命名法
            if(!(fieldName!=null&&!fieldName.isEmpty())){
                fieldName = AnnotationUtils.hump(field.getName());
            }

            //属性的访问权限
            boolean accessible = field.isAccessible();
            //修改访问权限
            field.setAccessible(true);
            //获取这个属性在obj这个类中的值
            Object o = null;
            try {
                o = field.get(obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            //记录第几个属性，
            len++;

            //insert xxx(xx,xx,xx) values(?,?,?)
            //update xxx set xxx = ?,xxx = ?
            //delete xxx where 1 = 1 and xxx = ?

            //拼sql
            if(step == 1){
                //当最后一个属性时，后缀不需要加  ，
                sql.append((flag?" , ":"")+fieldName);
                argsNum.append((flag?" , ":"")+" ? ");

                //判断该属性是不是id
                if(fieldName.equals(entityId)){
                    //id的话，添加自动分配id串
                    String tempId = UUID.randomUUID().toString().replace("-", "");
                    tempId = tempId.substring(tempId.length() / 2);
                    try {
                        field.set(obj,tempId);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    list.add(tempId);
                }else{
                    //不是id的话添加到集合中（参数）
                    list.add(o);
                }
            }else if(step == 2){
                //如果是id，则不形成拼串，因为id是作为更新或删除的条件
                if(!fieldName.equals(entityId)) {
                    sql.append((flag?" , ":"") + fieldName + " = ?");
                    list.add(o);
                }else{
                    continue;
                }
            }else if(step == 3){
                //删除：删除的sql只有条件，条件只有field和值，但是直接拼的话，
                // 你可以知道是否是最后一个属性，但不能知道最后一个属性有没有值，
                // 因此，只能将field和值都存进list中，后面再进行循环
                if(o!=null){
                    sql.append("and "+fieldName+"= ? ");
                    list.add(o);
                }
            }
            //访问权限修改回去
            field.setAccessible(accessible);
            flag = true;
            //System.out.println("object = " + o+" name = " + name);
        }

        if(step == 1){
            sql.append(") values("+argsNum+")");
        }else if(step == 2){
            sql.append(" where id = ?");
            list.add(id);
        }
        System.out.println(sql.toString());
        return update(sql.toString(), list.toArray());
    }

    /**
     * 判断本次操作是保存、更新还是删除
     * @param obj
     * @param sql
     * @param methodName
     * @param id
     * @return
     */
    public int autoExecute(Object obj,StringBuffer sql,String methodName,Object id){
        //类的名字：com....imglist
        String claName = obj.getClass().getName();
        if(!obj.getClass().isAnnotationPresent(TableName.class)){
            throw  new RuntimeException(obj.getClass()+" 没有@TableName注解！");
        }
        TableName tableName = obj.getClass().getAnnotation(TableName.class);
        String name = tableName.value();
        if(!(name!=null&&!name.isEmpty())){
            //驼峰命名法表明
            name = AnnotationUtils.hump(claName.substring(claName.lastIndexOf(".") + 1));
        }

        System.out.println("表名 = "+name);
        if(methodName.equals("saveOrUpdate")){//保存或更新方法
            //判断id是否存在   --  实体类注解暂时还没写，因此，id必须命名为id

            if(id == null){//不存在则是保存
                sql.append("insert into "+name+"(");
                return 1;
            }else{//存在id则是更新
                sql.append("update "+name+" set ");
                return 2;
            }
        }else{//删除方法：id和其他条件删除
            sql.append("delete from "+name+" where 1=1 ");
            return 3;
        }

    }

}